/*
 * Copyright (C) 2012-2016 TeraCN
 * 
 * This file is part of TeraCN.
 * 
 * TeraCN is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * TeraCN is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package tera.gameserver.network.serverpackets;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import rlib.util.array.Array;
import rlib.util.array.Arrays;
import rlib.util.table.IntKey;
import rlib.util.table.Table;

import tera.gameserver.model.playable.Player;
import tera.gameserver.model.skillengine.Skill;
import tera.gameserver.network.ServerPacketType;

/**
 * @author Ronn Mod Evestu
 */
public final class S_Skill_List extends ServerPacket
{
	private static final ServerPacket instance = new S_Skill_List();
	
	/**
	 * Method getInstance.
	 * @param player Player
	 * @return S_Skill_List
	 */
	public static S_Skill_List getInstance(Player player)
	{
		final S_Skill_List packet = (S_Skill_List) instance.newInstance();
		final ByteBuffer buffer = packet.getPrepare();
		
		try
		{
			final Table<IntKey, Skill> table = player.getSkills();
			final Array<Skill> skills = table.values(packet.getSkills());
			final Skill[] array = skills.array();
			int counter = 0;
			int skillsint = 0;
			int index = 8;
			
			for (int i = 0, length = skills.size(); i < length; i++)
			{
				final Skill skill = array[i];
				
				if ((skill.getLevel() < 2) && skill.isVisibleOnSkillList())
				{
					counter++;
				}
			}
			
			final int here = buffer.position();
			packet.writeShort(buffer, 0);
			packet.writeShort(buffer, 8);
			
			if (counter > 0)
			{
				for (int i = 0, length = skills.size(); i < length; i++)
				{
					final Skill skill = array[i];
					
					if ((skill.getLevel() < 2) && skill.isVisibleOnSkillList())
					{
						counter--;
						packet.writeShort(buffer, index);
						
						if (counter == 0)
						{
							index = 0;
						}
						else
						{
							index += 10;
						}
						
						packet.writeShort(buffer, index);
						packet.writeInt(buffer, skill.getId());
						packet.writeShort(buffer, skill.isActive() ? 1 : 0);
						++skillsint;
					}
				}
			}
			
			final int hereend = buffer.position();
			buffer.position(here);
			packet.writeShort(buffer, skillsint);
			buffer.position(hereend);
			return packet;
		}
		
		finally
		{
			buffer.flip();
		}
	}
	
	private final Array<Skill> skills;
	
	private final ByteBuffer prepare;
	
	public S_Skill_List()
	{
		skills = Arrays.toArray(Skill.class);
		prepare = ByteBuffer.allocate(4096).order(ByteOrder.LITTLE_ENDIAN);
	}
	
	/**
	 * Method finalyze.
	 * @see rlib.util.pools.Foldable#finalyze()
	 */
	@Override
	public void finalyze()
	{
		prepare.clear();
		skills.clear();
	}
	
	/**
	 * Method getPacketType.
	 * @return ServerPacketType
	 */
	@Override
	public ServerPacketType getPacketType()
	{
		return ServerPacketType.S_SKILL_LIST;
	}
	
	/**
	 * Method getPrepare.
	 * @return ByteBuffer
	 */
	public ByteBuffer getPrepare()
	{
		return prepare;
	}
	
	/**
	 * Method getSkills.
	 * @return Array<Skill>
	 */
	public Array<Skill> getSkills()
	{
		return skills;
	}
	
	/**
	 * Method isSynchronized.
	 * @return boolean
	 * @see rlib.network.packets.SendablePacket#isSynchronized()
	 */
	@Override
	public boolean isSynchronized()
	{
		return false;
	}
	
	/**
	 * Method writeImpl.
	 * @param buffer ByteBuffer
	 */
	@Override
	protected void writeImpl(ByteBuffer buffer)
	{
		writeOpcode(buffer);
		final ByteBuffer prepare = getPrepare();
		buffer.put(prepare.array(), 0, prepare.limit());
	}
}